using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Drawing;
using System.Reflection;
using System.Text;
using System.Windows.Forms;

namespace FreeFlowAdministrator
{
	/// <summary>
	/// Summary description for ExtendedDataGrid.
	/// </summary>
	public class ExtendedDataGrid : DataGrid
	{
    private ContextMenuStrip contextMenu;
    private IContainer components;
    private ToolStripMenuItem selectAllMenuItem;
    private ToolStripMenuItem copyToClipboardMenuItem;
    private DataGridTableStyle ts;
    public ExtendedDataGrid()
    {
      InitializeComponent();

      AllowNavigation = false;
      CaptionVisible = false;
      if (LicenseManager.UsageMode != LicenseUsageMode.Designtime)
      {
        ts = new DataGridTableStyle();
        TableStyles.Add(ts);
      }
    }

    public void RefreshGrid()
    {
      object dataSource = DataSource;
      DataSource = null;
      DataSource = dataSource;
      if (DataSource is IBindingList)
      {
        IBindingList list = (IBindingList)DataSource;
        list.ApplySort(list.SortProperty, list.SortDirection);
      }
      Refresh();
    }

    public void RemoveColumn(string columnName)
    {
      if (ts.GridColumnStyles.Contains(columnName))
        ts.GridColumnStyles.Remove(ts.GridColumnStyles[columnName]);
    }

    public void RemoveColumns(params string[] columnNames)
    {
      for (int i = 0; i < columnNames.Length; i++)
      {
        if (ts.GridColumnStyles.Contains(columnNames[i]))
          ts.GridColumnStyles.Remove(ts.GridColumnStyles[columnNames[i]]);
      }
    }

    public void ClearColumns()
    {
      ts.GridColumnStyles.Clear();
    }

    public void AddColumn(string columnName)
    {
      AddColumn(columnName, columnName);
    }

    public void AddColumn(string columnName, string caption)
    {
      int index = ts.GridColumnStyles.Add(new DataGridTextBoxColumn());
      ts.GridColumnStyles[index].MappingName = columnName;
      ts.GridColumnStyles[index].HeaderText = caption;
    }

    public void SetCaption(string columnName, string caption)
    {
      ts.GridColumnStyles[columnName].HeaderText = caption;
    }

    public void SetFormat(string columnName, string format)
    {
      ((DataGridTextBoxColumn)ts.GridColumnStyles[columnName]).Format = format;
    }

    protected override void OnDataSourceChanged (EventArgs e)
    {
      base.OnDataSourceChanged(e);
      if ((DataSource != null) && (ts != null))
      {
        if (DataSource is DataTable)
          ts.MappingName = ((DataTable)DataSource).TableName;
        else
          ts.MappingName = DataSource.GetType().Name;
      }
    }

    public void AutosizeColumns()
    {
      Type t = GetType();
      t = t.BaseType;
      MethodInfo m = t.GetMethod("ColAutoResize", BindingFlags.Instance | BindingFlags.NonPublic);

      for (int i = 0; (i < ts.GridColumnStyles.Count); i++)
      {
        DataGridColumnStyle style = ts.GridColumnStyles[i];
        
        m.Invoke(this, new object[] { i });
        // enforce maximum width to 200 (except for last column
        if (i < ts.GridColumnStyles.Count - 1)
          if (style.Width > 200)
            style.Width = 200;
      }
    }

    public void AutosizeRows()
    {
      int numRows = 0;
      if (DataSource is DataTable)
      {
        numRows = ((DataTable)DataSource).Rows.Count;
      }
      else if (DataSource is IList)
      {
        CurrencyManager manager = (CurrencyManager)BindingContext[DataSource];
        numRows = manager.List.Count;
      }

      using (Graphics g = Graphics.FromHwnd(Handle))
      {
        StringFormat sf = new StringFormat(StringFormat.GenericTypographic);

        // Since DataGridRows[] is not exposed directly by the DataGrid  
        // we use reflection to hack internally to it..
        MethodInfo mi = GetType().GetMethod("get_DataGridRows",
          BindingFlags.Instance | BindingFlags.NonPublic);

        Array dgra = (Array)mi.Invoke(this, null);

        // Convert this to an ArrayList, little bit easier to deal with 
        // that way, plus we can strip out the newrow row. 
        List<object> DataGridRows = new List<object>();
        foreach (object dgrr in dgra)
        {
          if (dgrr.ToString().EndsWith("DataGridRelationshipRow"))
            DataGridRows.Add(dgrr);
        }

        int colCount = TableStyles[0].GridColumnStyles.Count;

        // Now loop through all the rows in the grid 
        for (int i = 0; i < numRows; ++i)
        {
          int maxHeight = 0;

          for (int j = 0; j < colCount; j++)
          {
            DataGridColumnStyle style = ts.GridColumnStyles[j];
            SizeF size = g.MeasureString(this[i, j].ToString(), Font, style.Width+10, sf);
            int h = Convert.ToInt32(size.Height);

            // Little extra cellpadding space 
            h = h + 8;

            maxHeight = Math.Max(h, maxHeight);
          }

          // Now we pick that row out of the DataGridRows[] Array  
          // that we have and set it's Height property to what we 
          // think it should be. 
          PropertyInfo pi = DataGridRows[i].GetType().GetProperty("Height");
          pi.SetValue(DataGridRows[i], maxHeight, null);
        }
      }
    }

    public int DeleteSelected()
    {
      int count = 0;
      BindingManagerBase bm = BindingContext[DataSource];
      for (int i = bm.Count-1; i >= 0; i--) 
      { 
        if(IsSelected(i))
        {
          bm.RemoveAt(i);
          count++;
        }
      }

      CurrentRowIndex = -1;
      RefreshGrid();
      return count;
    }

    public void CopyToClipboard()
    {
      if (DataSource != null)
      {
        StringBuilder builder = new StringBuilder();
        for (int i = 0; i < ts.GridColumnStyles.Count; i++)
        {
          if (i > 0)
            builder.Append("\t");
          builder.Append(ts.GridColumnStyles[i].HeaderText);
        }
        builder.Append(Environment.NewLine);

        CurrencyManager manager = (CurrencyManager)BindingContext[DataSource];

        if (DataSource is DataTable)
        {
          DataTable dt = (DataTable)DataSource;
          foreach(DataRowView r in manager.List)
          {
            for (int i = 0; i < dt.Columns.Count; i++)
            {
              if (i > 0)
                builder.Append("\t");
              builder.Append(r[i].ToString());
            }
            builder.Append(Environment.NewLine);
          }
        }
        else if (DataSource is IList)
        {
          for (int i = 0; i < manager.List.Count; i++)
          {
            object item = manager.List[i];
            Type objectType = item.GetType();
            for (int j = 0; j < ts.GridColumnStyles.Count; j++)
            {
              if (j > 0)
                builder.Append("\t");
              string colName = ts.GridColumnStyles[j].MappingName;
              PropertyInfo propInfo = objectType.GetProperty(colName);
              if (propInfo != null)
              {
                object propertyValue = propInfo.GetValue(item, null);
                builder.Append(propertyValue.ToString());
              }
              else
                Debug.Assert(false, "Property not found - " + colName);
            }
            builder.Append(Environment.NewLine);
          }
        }
        else
          throw new NotSupportedException();

        Clipboard.SetDataObject(builder.ToString(), true);
      }
    }

    public void SelectAll()
    {
      BindingManagerBase bm = BindingContext[DataSource];
      for (int i = 0; i < bm.Count; i++)
      {
        Select(i);
      }
    }

    protected override void OnClick (EventArgs e)
    {
      base.OnClick(e);
      Point client = PointToClient(Cursor.Position);
      HitTestInfo hitInfo = HitTest(client);
      if ((hitInfo.Column == -1) && (hitInfo.Row == -1))
      {
        if (TableStyles[0].GridColumnStyles.Count > 0)
          if (client.X < TableStyles[0].GridColumnStyles[0].Width)
            if (client.Y < TableStyles[0].PreferredRowHeight)
              SelectAll();
      }
    }

    public event EventHandler OpenSelected;
    protected override void OnDoubleClick(EventArgs e)
    {
      base.OnDoubleClick(e);
      Point client = PointToClient(Cursor.Position);
      HitTestInfo hitInfo = HitTest(client);
      if (hitInfo.Column == -1)
      {
        if (OpenSelected != null)
          OpenSelected(this, EventArgs.Empty);
      }
    }

    private void InitializeComponent()
    {
      this.components = new System.ComponentModel.Container();
      this.contextMenu = new System.Windows.Forms.ContextMenuStrip(this.components);
      this.selectAllMenuItem = new System.Windows.Forms.ToolStripMenuItem();
      this.copyToClipboardMenuItem = new System.Windows.Forms.ToolStripMenuItem();
      this.contextMenu.SuspendLayout();
      ((System.ComponentModel.ISupportInitialize)(this)).BeginInit();
      this.SuspendLayout();
      // 
      // contextMenu
      // 
      this.contextMenu.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
            this.selectAllMenuItem,
            this.copyToClipboardMenuItem});
      this.contextMenu.Name = "contextMenu";
      this.contextMenu.Size = new System.Drawing.Size(170, 48);
      // 
      // selectAllMenuItem
      // 
      this.selectAllMenuItem.Name = "selectAllMenuItem";
      this.selectAllMenuItem.Size = new System.Drawing.Size(169, 22);
      this.selectAllMenuItem.Text = "Select All";
      this.selectAllMenuItem.Click += new System.EventHandler(this.selectAllMenuItem_Click);
      // 
      // copyToClipboardMenuItem
      // 
      this.copyToClipboardMenuItem.Image = global::FreeFlowAdministrator.Properties.Resources.copy1;
      this.copyToClipboardMenuItem.Name = "copyToClipboardMenuItem";
      this.copyToClipboardMenuItem.Size = new System.Drawing.Size(169, 22);
      this.copyToClipboardMenuItem.Text = "Copy to clipboard";
      this.copyToClipboardMenuItem.Click += new System.EventHandler(this.copyToClipboardMenuItem_Click);
      // 
      // ExtendedDataGrid
      // 
      this.ContextMenuStrip = this.contextMenu;
      this.contextMenu.ResumeLayout(false);
      ((System.ComponentModel.ISupportInitialize)(this)).EndInit();
      this.ResumeLayout(false);

    }

    private void copyToClipboardMenuItem_Click(object sender, EventArgs e)
    {
      CopyToClipboard();
    }

    private void selectAllMenuItem_Click(object sender, EventArgs e)
    {
      SelectAll();
    }
	}
}
